using System;
using System.Globalization;
using System.Xml;
using Legacy.Core;
using Legacy.Core.SaveGameManagement;

namespace MMXSaveGameConverter
{
    internal static class Xml2Save
    {
        public static SaveGameMeta GetSaveMeta(XmlDocument xmlDocument)
        {
            XmlElement node = xmlDocument["SavedGame"];
            if (node == null)
                throw new Exception("SaveGame node is not found.");

            node = node["SaveGameMeta"];
            if (node == null)
                throw new Exception("SaveGame node is not found.");

            return DeserializeMeta(node);
        }

        private static SaveGameMeta DeserializeMeta(XmlElement meta)
        {
            Int64 timeInTicks = Int64.Parse(meta.Attributes["Int64_TimeInTicks"].Value, CultureInfo.InvariantCulture);
            Int64 playTimeInTicks = Int64.Parse(meta.Attributes["Int64_PlayTimeInTicks"].Value, CultureInfo.InvariantCulture);
            Int32 saveNumber = Int32.Parse(meta.Attributes["Int32_SaveNumber"].Value, CultureInfo.InvariantCulture);
            Int32 saveGameType = Int32.Parse(meta.Attributes["Int32_SaveGameType"].Value, CultureInfo.InvariantCulture);
            Int32 difficulty = Int32.Parse(meta.Attributes["Int32_Difficulty"].Value, CultureInfo.InvariantCulture);

            return new SaveGameMeta(new DateTime(timeInTicks), new TimeSpan(playTimeInTicks), saveNumber, (ESaveGameType)saveGameType, (EDifficulty)difficulty);
        }

        public static SaveGame GetSaveGame(XmlDocument xmlDocument, SaveGameMeta meta)
        {
            SaveGame sg = new SaveGame(meta);

            XmlElement root = xmlDocument["SavedGame"];
            if (root == null)
                throw new Exception("SaveGame node is not found.");

            foreach (XmlNode child in root.ChildNodes)
            {
                if (child.Name == "SaveGameData")
                    sg.Add(Deserialize((XmlElement)child));
            }

            return sg;
        }

        private static SaveGameData Deserialize(XmlElement node)
        {
            SaveGameData result = new SaveGameData(node.Attributes["id"].Value);

            foreach (XmlElement element in node.ChildNodes)
                foreach (XmlElement entry in element.ChildNodes)
                {
                    try
                    {
                        if (element.Name == XmlHelper.Object)
                        {
                            SaveGameData data = Deserialize(entry);
                            result.Set(data.ID, Deserialize(entry));
                            continue;
                        }

                        string name = entry.Attributes["name"].Value;
                        string value = entry.Attributes["value"].Value;

                        if (element.Name == XmlHelper.Boolean)
                            result.Set(name, Boolean.Parse(value));
                        else if (element.Name == XmlHelper.Byte)
                            result.Set(name, Byte.Parse(value, CultureInfo.InvariantCulture));
                        else if (element.Name == XmlHelper.Int16)
                            result.Set(name, Int16.Parse(value, CultureInfo.InvariantCulture));
                        else if (element.Name == XmlHelper.UInt16)
                            result.Set(name, UInt16.Parse(value, CultureInfo.InvariantCulture));
                        else if (element.Name == XmlHelper.Int32)
                            result.Set(name, Int32.Parse(value, CultureInfo.InvariantCulture));
                        else if (element.Name == XmlHelper.UInt32)
                            result.Set(name, UInt32.Parse(value, CultureInfo.InvariantCulture));
                        else if (element.Name == XmlHelper.Int64)
                            result.Set(name, Int64.Parse(value, CultureInfo.InvariantCulture));
                        else if (element.Name == XmlHelper.UInt64)
                            result.Set(name, UInt64.Parse(value, CultureInfo.InvariantCulture));
                        else if (element.Name == XmlHelper.Single)
                            result.Set(name, Single.Parse(value, CultureInfo.InvariantCulture));
                        else if (element.Name == XmlHelper.Double)
                            result.Set(name, Double.Parse(value, CultureInfo.InvariantCulture));
                        else if (element.Name == XmlHelper.String)
                            result.Set(name, value);
                        else
                            throw new Exception(String.Format("Unknown element name: {0}", element.Name));
                    }
                    catch (Exception ex)
                    {
                        throw new Exception(String.Format("Failed to process node: {0}", entry.InnerXml), ex);
                    }
                }

            return result;
        }
    }
}